package hu.jonas.junitmax.handlers;

import hu.jonas.junitmax.TestResultViewPart;

import java.util.HashSet;
import java.util.Set;

import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.ILaunchConfigurationType;
import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
import org.eclipse.debug.core.ILaunchManager;
import org.eclipse.jdt.core.IJavaModel;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.search.IJavaSearchConstants;
import org.eclipse.jdt.core.search.IJavaSearchScope;
import org.eclipse.jdt.core.search.SearchEngine;
import org.eclipse.jdt.core.search.SearchMatch;
import org.eclipse.jdt.core.search.SearchParticipant;
import org.eclipse.jdt.core.search.SearchPattern;
import org.eclipse.jdt.core.search.SearchRequestor;
import org.eclipse.jdt.internal.junit.launcher.JUnitLaunchConfigurationConstants;
import org.eclipse.jdt.internal.junit.launcher.TestKindRegistry;
import org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.handlers.HandlerUtil;

@SuppressWarnings("restriction")
public class RunAllTests extends AbstractHandler {

	@Override
	public Object execute(ExecutionEvent event) throws ExecutionException {
		
		ILaunchManager launchManager = DebugPlugin.getDefault().getLaunchManager();
		ILaunchConfigurationType lcType =
			launchManager.getLaunchConfigurationType(JUnitLaunchConfigurationConstants.ID_JUNIT_APPLICATION);
		
		IWorkbenchWindow window = HandlerUtil.getActiveWorkbenchWindowChecked(event);
		
		TestResultViewPart testResultView =
			(TestResultViewPart) window.getActivePage().findView(TestResultViewPart.VIEWPART_ID);
		
		try {
			ILaunchConfigurationWorkingCopy launchConfiguration = lcType.newInstance(null, "RunAllTests");
			launchConfiguration.setAttribute(
					JUnitLaunchConfigurationConstants.ATTR_TEST_RUNNER_KIND,
					TestKindRegistry.JUNIT4_TEST_KIND_ID
				);
			
			IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot();
			IJavaModel javaModel = JavaCore.create(workspaceRoot);
			IJavaProject[] javaProjects = javaModel.getJavaProjects();
		
			SearchEngine search = new SearchEngine();
			SearchPattern pattern = SearchPattern.createPattern(
					"org.junit.Test",
					IJavaSearchConstants.ANNOTATION_TYPE,
					IJavaSearchConstants.ANNOTATION_TYPE_REFERENCE,
					SearchPattern.R_EXACT_MATCH | SearchPattern.R_CASE_SENSITIVE
				);
				
			SearchParticipant[] participants = new SearchParticipant[] {
					SearchEngine.getDefaultSearchParticipant()
			};
			IJavaSearchScope scope = SearchEngine.createJavaSearchScope(javaProjects, IJavaSearchScope.SOURCES);
			TestMethodSearchRequestor requestor = new TestMethodSearchRequestor();

			search.search(pattern, participants, scope, requestor, null);
			
			IMethod[] methods = requestor.getMethods();
			
			testResultView.startRunTests(methods.length);
			
			for (IJavaProject javaProject : javaProjects) {
				launchConfiguration.setAttribute(
						IJavaLaunchConfigurationConstants.ATTR_PROJECT_NAME,
						javaProject.getElementName()
					);
				
				launchConfiguration.setAttribute(
						JUnitLaunchConfigurationConstants.ATTR_TEST_CONTAINER,
						javaProject.getHandleIdentifier()
					);
				
				launchConfiguration.launch(ILaunchManager.RUN_MODE, null);
			}
			
		} catch (CoreException e) {
			e.printStackTrace();
		}
		
		return null;
	}

	private class TestMethodSearchRequestor extends SearchRequestor {

		private Set<IMethod> testMethods = new HashSet<IMethod>();
		
		@Override
		public void acceptSearchMatch(SearchMatch match) throws CoreException {
			Object element = match.getElement();
			
			if (element instanceof IMethod) {
				IMethod method = (IMethod) element;
				
				testMethods.add(method);
			}
		}
		
		public IMethod[] getMethods() {
			return testMethods.toArray(new IMethod[0]);
		}
		
	}
	
}
